package edu.yctc.origin.service.impl;

import java.util.List;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Service;

import edu.yctc.origin.constant.ResultCode;
import edu.yctc.origin.dao.AuthorDAO;
import edu.yctc.origin.dao.BookDAO;
import edu.yctc.origin.dao.PressDAO;
import edu.yctc.origin.dao.StockDAO;
import edu.yctc.origin.entity.AuthorDO;
import edu.yctc.origin.entity.BookDO;
import edu.yctc.origin.entity.PressDO;
import edu.yctc.origin.entity.ResultDO;
import edu.yctc.origin.entity.StockDO;
import edu.yctc.origin.service.ManageIService;
import edu.yctc.origin.vo.BookVO;

/**
 * 图书管理业务层实现
 * 
 * @author 赵宜珺
 *
 */
@ComponentScan({"edu.yctc.origin.dao"})
@Service("manageService")
public class ManageServiceImpl implements ManageIService {

    private final static Logger LOG = LoggerFactory.getLogger("serviceLogger");

    private final static int FIRST_STOCK = 1;

    private final static int ADDED_STOCK = 1;

    private final static int REDUCED_STOCK = -1;

    @Resource
    private BookDAO bookDAO;

    @Resource
    private PressDAO pressDAO;

    @Resource
    private StockDAO stockDAO;

    @Resource
    private AuthorDAO authorDAO;

    @Override
    public ResultDO<Void> insertBook(BookVO bookVO) {
        if (StringUtils.isBlank(bookVO.getName()) || StringUtils.isBlank(bookVO.getNumber())
            || StringUtils.isBlank(bookVO.getAuthor()) || StringUtils.isBlank(bookVO.getPress())) {
            LOG.error("insert book fail, parameter invalid, bookVO={}", bookVO);
            return new ResultDO<>(false, ResultCode.PARAMETER_INVALID, ResultCode.MSG_PARAMETER_INVALID);
        }
        try {
            // 检验number唯一索引
            BookDO checkNumber = bookDAO.getBookDOByNumber(bookVO.getNumber());
            if (checkNumber != null) {
                LOG.error("insert book fail, already exist the book, number={}, bookDO={}", checkNumber.getNumber(),
                    checkNumber);
                return new ResultDO<Void>(false, ResultCode.ALREADY_EXIST_THE_BOOK,
                    ResultCode.MSG_ALREADY_EXIST_THE_BOOK);
            }
            String author = bookVO.getAuthor();
            String press = bookVO.getPress();
            // 判断数据库中查是否存在该作者
            AuthorDO authorDO = authorDAO.getAuthorDOByName(author);
            // 没找到则插入
            if (authorDO == null) {
                authorDO = new AuthorDO();
                authorDO.setName(author);
                authorDAO.insert(authorDO);
            }
            // 判断数据库中是否存在该出版社
            PressDO pressDO = pressDAO.getPressDOByName(press);
            if (pressDO == null) {
                pressDO = new PressDO();
                pressDO.setName(press);
                pressDAO.insert(pressDO);
            }
            // 判断数据库是否已存在该书
            BookDO bookDO = bookDAO.getBookDOByNameAndNumberAndPressIdAndAuthorId(bookVO.getName(),
                bookVO.getNumber(), pressDO.getId(), authorDO.getId());
            // 无该书记录
            if (bookDO == null) {
                bookDO = new BookDO();
                bookDO.setName(bookVO.getName());
                bookDO.setNumber(bookVO.getNumber());
                bookDO.setAuthorId(authorDO.getId());
                bookDO.setPressId(pressDO.getId());
                bookDAO.insert(bookDO);
            }
            // 库存增加
            // 判断数据库中是否存在该书库存记录
            StockDO stockDO = stockDAO.getStockDOByBookId(bookDO.getId());
            // 没找到则插入
            if (stockDO == null) {
                stockDO = new StockDO();
                stockDO.setBookId(bookDO.getId());
                stockDO.setStock(FIRST_STOCK);
                stockDAO.insert(stockDO);
                LOG.info("insert book success, bookVO={}", bookVO);
                return new ResultDO<>(true, ResultCode.SUCCESS, ResultCode.MSG_SUCCESS);
            }
            // 已有记录
            // 库存增加
            stockDO.setStock(stockDO.getStock() + ADDED_STOCK);
            stockDAO.update(stockDO);
            LOG.info("insert book success, bookVO={}", bookVO);
            return new ResultDO<>(true, ResultCode.SUCCESS, ResultCode.MSG_SUCCESS);
        } catch (Exception e) {
            LOG.error("insert book error, bookVO={}", bookVO, e);
            return new ResultDO<>(false, ResultCode.ERROR_SYSTEM_EXCEPTION, ResultCode.MSG_ERROR_SYSTEM_EXCEPTION);
        }
    }

    @Override
    public ResultDO<Void> modifyBook(BookVO bookVO) {
        if (StringUtils.isBlank(bookVO.getName()) || StringUtils.isBlank(bookVO.getNumber())
            || StringUtils.isBlank(bookVO.getAuthor()) || StringUtils.isBlank(bookVO.getPress()) || bookVO.getId() <= 0
            || bookVO.getStock() < 0) {
            LOG.error("modify book fail, parameter invali, bookVO={}", bookVO);
            return new ResultDO<>(false, ResultCode.PARAMETER_INVALID, ResultCode.MSG_PARAMETER_INVALID);
        }
        try {
            BookDO bookDO = bookDAO.getBookDOById(bookVO.getId());
            String author = bookVO.getAuthor();
            String press = bookVO.getPress();
            // 判断数据库中查是否存在该作者
            AuthorDO authorDO = authorDAO.getAuthorDOByName(author);
            // 没找到则插入
            if (authorDO == null) {
                authorDO = new AuthorDO();
                authorDO.setName(author);
                authorDAO.insert(authorDO);
            }
            // 判断数据库中是否存在该出版社
            PressDO pressDO = pressDAO.getPressDOByName(press);
            if (pressDO == null) {
                pressDO = new PressDO();
                pressDO.setName(press);
                pressDAO.insert(pressDO);
            }
            bookDO.setAuthorId(authorDO.getId());
            bookDO.setPressId(pressDO.getId());
            bookDO.setName(bookVO.getName());
            bookDO.setNumber(bookVO.getNumber());
            // 更新
            bookDAO.update(bookDO);
            LOG.info("modify book success, bookDO={}", bookDO);
            return new ResultDO<>(true, ResultCode.SUCCESS, ResultCode.MSG_SUCCESS);
        } catch (Exception e) {
            LOG.error("mofify book error, bookVO={}", bookVO, e);
            return new ResultDO<>(false, ResultCode.ERROR_SYSTEM_EXCEPTION, ResultCode.MSG_ERROR_SYSTEM_EXCEPTION);
        }
    }

    @Override
    public ResultDO<Void> lendBook(long id) {
        if (id <= 0) {
            LOG.error("lend book fail, parameter invalid, id={}", id);
            return new ResultDO<>(false, ResultCode.PARAMETER_INVALID, ResultCode.MSG_PARAMETER_INVALID);
        }
        // 存在性检验
        BookDO bookDO = bookDAO.getBookDOById(id);
        StockDO stockDO = stockDAO.getStockDOByBookId(id);
        if (bookDO == null || stockDO == null) {
            LOG.error("lend book fail, no such book, id={}, bookDO={}, stockDO={}", id, bookDO, stockDO);
            return new ResultDO<>(false, ResultCode.DB_ERROR, ResultCode.MSG_DB_ERROR);
        }
        try {
            // 如果库存不足, 无法借出
            if (stockDO.getStock() <= 0) {
                LOG.info("lend book fail, lack of stock, id={}, bookDO={}, stockDO={}", id, bookDO, stockDO);
                return new ResultDO<>(false, ResultCode.LACK_OF_STOCK, ResultCode.MSG_LACK_OF_STOCK);
            }
            // 借出，库存减少
            stockDO.setStock(stockDO.getStock() + REDUCED_STOCK);
            stockDAO.update(stockDO);
            LOG.info("lend book success, id={}, bookDO={}, stockDO={}", id, bookDO, stockDO);
            return new ResultDO<>(true, ResultCode.SUCCESS, ResultCode.MSG_SUCCESS);
        } catch (Exception e) {
            LOG.error("lend book error, id={}", id, e);
            return new ResultDO<>(false, ResultCode.ERROR_SYSTEM_EXCEPTION, ResultCode.MSG_ERROR_SYSTEM_EXCEPTION);
        }
    }

    @Override
    public ResultDO<List<BookDO>> getBookDOsByName(String name) {
        if (StringUtils.isBlank(name)) {
            LOG.error("get bookDOs by name fail, parameter invalid, name={}", name);
            return new ResultDO<List<BookDO>>(false, ResultCode.PARAMETER_INVALID, ResultCode.MSG_PARAMETER_INVALID,
                null);
        }
        try {
            List<BookDO> bookDOs = bookDAO.getBookDOsByName(name);
            LOG.info("get bookDOs by name success, name={}", name);
            return new ResultDO<List<BookDO>>(true, ResultCode.SUCCESS, ResultCode.MSG_SUCCESS, bookDOs);
        } catch (Exception e) {
            LOG.error("get bookDOs by name error, name={}", name);
            return new ResultDO<List<BookDO>>(false, ResultCode.ERROR_SYSTEM_EXCEPTION,
                ResultCode.MSG_ERROR_SYSTEM_EXCEPTION, null);
        }
    }

    @Override
    public ResultDO<BookVO> getBookVOByBookDO(BookDO bookDO) {
        if (StringUtils.isBlank(bookDO.getName()) || StringUtils.isBlank(bookDO.getNumber())
            || bookDO.getAuthorId() <= 0 || bookDO.getPressId() <= 0) {
            LOG.error("get bookVO by bookDO fail, parameter invalid, bookDO={}", bookDO);
            return new ResultDO<BookVO>(false, ResultCode.PARAMETER_INVALID, ResultCode.MSG_PARAMETER_INVALID, null);
        }
        try {
            BookVO bookVO = new BookVO();
            bookVO.setId(bookDO.getId());
            bookVO.setName(bookDO.getName());
            bookVO.setNumber(bookDO.getNumber());
            bookVO.setAuthor(authorDAO.getAuthorDOById(bookDO.getAuthorId()).getName());
            bookVO.setPress(pressDAO.getPressDOById(bookDO.getPressId()).getName());
            bookVO.setStock(stockDAO.getStockDOByBookId(bookDO.getId()).getStock());
            LOG.info("get bookVO by bookDO success, bookDO={}, bookVO={}", bookDO, bookVO);
            return new ResultDO<BookVO>(true, ResultCode.SUCCESS, ResultCode.MSG_SUCCESS, bookVO);
        } catch (Exception e) {
            LOG.error("get bookVO by bookDO error, bookDO={}", bookDO);
            return new ResultDO<BookVO>(false, ResultCode.ERROR_SYSTEM_EXCEPTION, ResultCode.MSG_ERROR_SYSTEM_EXCEPTION,
                null);
        }
    }

}
